﻿namespace DCHealthCheck.MvcWeb.Classes.DataServices {

    #region Usings
    using DCHealthCheck.DomainModel;
    using DCHealthCheck.MvcWeb.Classes.ViewModels;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Caching;
    using System.Web.Mvc;
    #endregion

    public abstract class BaseDataService : IBaseDataService {

        #region Members
        private Dictionary<Guid, DomainController> AllDomainControllers { get; set; }
        private Dictionary<Guid, Guid> AllSystemInfoDCXRef { get; set; }
        private IRepository<DomainController, IEntityManager> DCRepository;
        #endregion

        #region Constructor
        public BaseDataService(IRepository<DomainController, IEntityManager> dcRepository) {
            if (dcRepository == null) {
                throw new ArgumentNullException("dcRepository");
            }

            this.DCRepository = dcRepository;
            this.AllDomainControllers = new Dictionary<Guid, DomainController>();
            this.AllSystemInfoDCXRef = new Dictionary<Guid, Guid>();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Builds the SelectList collections for ADSites, Domains, DCNames, and OSVersion
        /// </summary>
        /// <param name="filteredDCIds"></param>
        /// <param name="viewModel">The ViewModel</param>
        public virtual void BuildFilterSelectLists<T>(List<Guid> filteredDCIds, T viewModel) where T : IBaseViewModel {
            //Global.DefaultLog.DebugFormat("[ThreadId: {0}] {1}", Thread.CurrentThread.ManagedThreadId, Extensions.CurrentMethodName());

            var selectListItem = new SelectListItem();
            selectListItem.Text = "(Any)";
            selectListItem.Value = string.Empty;

            viewModel.ADSiteSelectListItems.Add(selectListItem);
            viewModel.DomainSelectListItems.Add(selectListItem);
            viewModel.DCNameSelectListItems.Add(selectListItem);
            viewModel.OSVersionSelectListItems.Add(selectListItem);

            var domains = new List<string>();
            var sites = new List<string>();
            var dcNames = new List<string>();
            var osVersions = new List<string>();

            GetCachedDCsAndResults(viewModel);

            var filteredDomainControllers = new Dictionary<Guid, DCHealthCheck.DomainModel.DomainController>();
            var filteredSystemInfoDCXRef = new Dictionary<Guid, Guid>();

            foreach (var id in this.AllDomainControllers.Keys.ToList()) {
                if (filteredDCIds.Any(x => x == id)) {
                    filteredDomainControllers.Add(id, this.AllDomainControllers[id]);
                }
            }

            foreach (var systemInfoId in this.AllSystemInfoDCXRef.Keys.ToList()) {
                if (filteredDCIds.Any(x => x == this.AllSystemInfoDCXRef[systemInfoId])) {
                    filteredSystemInfoDCXRef.Add(systemInfoId, this.AllSystemInfoDCXRef[systemInfoId]);
                }
            }

            if (viewModel.DomainControllerId != Guid.Empty) {
                viewModel.DCName = filteredDomainControllers[viewModel.DomainControllerId].SamAccountName;
            }
            else if (viewModel.SystemInfoId != Guid.Empty) {
                viewModel.DCName = filteredDomainControllers[filteredSystemInfoDCXRef[viewModel.SystemInfoId]].SamAccountName;
            }

            domains = filteredDomainControllers.Values
                .Where(x => viewModel.IsNotFilteredDomainController(x))
                .Select(x => x.NetbiosDomain)
                .Distinct()
                .OrderBy(x => x)
                .ToList();

            sites = filteredDomainControllers.Values
                .Where(x => viewModel.IsNotFilteredDomainController(x))
                .Select(x => x.ADSite)
                .Distinct()
                .OrderBy(x => x)
                .ToList();

            dcNames = filteredDomainControllers
                .Where(x => viewModel.IsNotFilteredDomainController(x.Value))
                .Select(x => x.Value.SamAccountName)
                .OrderBy(x => x)
                .ToList();

            osVersions = filteredDomainControllers.Values
                .Where(x => viewModel.IsNotFilteredDomainController(x))
                .Select(x => x.OSVersion)
                .Distinct()
                .OrderBy(x => x)
                .ToList();

            foreach (var domain in domains) {
                selectListItem = new SelectListItem();
                selectListItem.Text = domain;
                if (!string.IsNullOrWhiteSpace(viewModel.Domain) && string.Equals(viewModel.Domain, domain, StringComparison.OrdinalIgnoreCase)) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = domain;
                viewModel.DomainSelectListItems.Add(selectListItem);
            }

            foreach (var site in sites) {
                selectListItem = new SelectListItem();
                selectListItem.Text = site;
                if (!string.IsNullOrWhiteSpace(viewModel.ADSite) && string.Equals(viewModel.ADSite, site, StringComparison.OrdinalIgnoreCase)) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = site;
                viewModel.ADSiteSelectListItems.Add(selectListItem);
            }

            foreach (var dcName in dcNames) {
                selectListItem = new SelectListItem();
                selectListItem.Text = dcName.Replace("$", string.Empty);

                bool dcMatch =
                    (!string.IsNullOrWhiteSpace(viewModel.DCName) && string.Equals(viewModel.DCName, dcName, StringComparison.OrdinalIgnoreCase));

                if (dcMatch) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = dcName;
                viewModel.DCNameSelectListItems.Add(selectListItem);
            }

            foreach (var osversion in osVersions) {
                selectListItem = new SelectListItem();
                selectListItem.Text = osversion;
                if (!string.IsNullOrWhiteSpace(viewModel.OSVersion) && string.Equals(viewModel.OSVersion, osversion, StringComparison.OrdinalIgnoreCase)) {
                    selectListItem.Selected = true;
                }
                selectListItem.Value = osversion;
                viewModel.OSVersionSelectListItems.Add(selectListItem);
            }
        }

        private void GetCachedDCsAndResults<T>(T viewModel) where T : IBaseViewModel {
            this.AllDomainControllers = HttpContext.Current.Cache["allDomainControllers"] as Dictionary<Guid, DomainController>;
            this.AllSystemInfoDCXRef = HttpContext.Current.Cache["allSystemInfoDCXRef"] as Dictionary<Guid, Guid>;

            if ((this.AllDomainControllers == null) || (this.AllSystemInfoDCXRef == null)) {
                this.AllDomainControllers = this.DCRepository.Get()
                    .ToDictionary(x => x.Id, x => x);

                this.AllSystemInfoDCXRef = this.DCRepository.Get()
                    .SelectMany(x => x.SystemInfos)
                    .Select(x => new { x.Id, x.DomainControllerId })
                    .ToDictionary(x => x.Id, x => x.DomainControllerId);

                HttpContext.Current.Cache.Add("allDomainControllers", this.AllDomainControllers, null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
                HttpContext.Current.Cache.Add("allSystemInfoDCXRef", this.AllSystemInfoDCXRef, null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }
        }

        /// <summary>
        /// Gets the DateTime of the most recent HealthCheck run
        /// </summary>
        /// <returns>The DateTime of the most recent healthCheck SystemInfo object</returns>
        public DateTime GetMostRecentResultDateTime() {
            var mostRecentResultCheckDateTime = DateTime.UtcNow.Date.AddDays(-30);
            var mostRecentResult = this.DCRepository.Get()
                .SelectMany(x => x.SystemInfos)
                .OrderByDescending(x => x.CheckDateTimeUTC)
                .FirstOrDefault();

            if (mostRecentResult != null) {
                mostRecentResultCheckDateTime = mostRecentResult.CheckDateTimeUTC;
            }

            return mostRecentResultCheckDateTime;
        }
        #endregion
    }
}